package com.nulldev.util.networking.async2.tcp.listeners.packets;

import java.util.concurrent.RejectedExecutionException;

import com.nulldev.util.networking.async2.DataFrame;
import com.nulldev.util.networking.async2.events.ManualResetEvent;
import com.nulldev.util.networking.async2.tcp.listeners.TCPClientConnection;

public final class IncomingTCPClientConnectionPacket implements Runnable {

	public final ManualResetEvent fDone = new ManualResetEvent(false);
	private final TCPClientConnection fClient;
	private final DataFrame fData;
	private IncomingTCPClientConnectionPacket fPreviousPacket;
	public boolean fCancel = false;

	/**
	 * Constructs a new incoming packet for an existing TCP client connection. Use
	 * this class to receive data from a client. This is an incoming message that
	 * will remain in the servers thread pool as a job for the thread pool workers.
	 *
	 * @param client         is the client where this message belongs to.
	 * @param data           is a DataFrame class.
	 * @param previousPacket is the previous incoming message of the client.
	 */
	public IncomingTCPClientConnectionPacket(TCPClientConnection client, DataFrame data, IncomingTCPClientConnectionPacket previousPacket) {
		fClient = client;
		fData = data;
		fPreviousPacket = previousPacket;

		sendToThreadPool();
	}

	protected void sendToThreadPool() {
		try {
			fClient.fServer.fMyThreadPool.execute(this);
		} catch (RejectedExecutionException ex) {
			fClient.forceDisconnect();
		}
	}

	/**
	 * Cancel this incoming packet.
	 *
	 * By calling this method this and all the previous incoming packets that are
	 * stored in the thread pool will be canceled. Call this method for the last
	 * incoming packet of the client when the client disconnects.
	 */
	public void cancel() {
		fCancel = true;
		fDone.set();
	}

	@Override
	public void run() {
		try {
			if (fPreviousPacket == null) {
				fClient.fServer.onDataReceive(fClient, fData);
			} else {
				fPreviousPacket.fDone.waitOne();
				if (!fCancel && !fPreviousPacket.fCancel) {
					fClient.fServer.onDataReceive(fClient, fData);
				} else {
					fCancel = true;
				}
			}
		} catch (Exception ex) {
		}

		if (fPreviousPacket != null) {
			fPreviousPacket = null;
		}
		fDone.set();
	}

	/**
	 * Returns the data of this packet.
	 *
	 * @return the data of this packet.
	 */
	public DataFrame getData() {
		return fData;
	}
}